package com.example.mdc.logback.common.utils;


import com.alibaba.fastjson.JSON;
import com.example.mdc.logback.common.config.okhttp.OkHttpLoggingInterceptor;
import lombok.Getter;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author: liu_pc
 * Date:        2023/8/7
 * Description: 封装OKHttpUtil常用方法
 * Version:     1.0
 */
@Getter
public class OkHttpUtil {

    private static final Logger logger = LoggerFactory.getLogger(OkHttpUtil.class);
    private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
    private static final MediaType FORM_MEDIA_TYPE = MediaType.parse("application/x-www-form-urlencoded");

    private Map<String, String> headerMap;
    @Getter
    private Map<String, Object> paramMap;
    @Getter
    private String url;
    private Request.Builder request;

    private static final OkHttpClient CLIENT = new OkHttpClient.Builder()
            .addNetworkInterceptor(new OkHttpLoggingInterceptor())
            .build();


    public static OkHttpUtil builder() {
        return new OkHttpUtil();
    }

    public OkHttpUtil url(String url) {
        this.url = url;
        return this;
    }

    public OkHttpUtil addHeader(String key, String value) {
        if (headerMap == null) {
            headerMap = new LinkedHashMap<>(16);
        }
        headerMap.put(key, value);
        return this;
    }

    public OkHttpUtil addParam(String key, Object value) {
        if (paramMap == null) {
            paramMap = new LinkedHashMap<>(16);
        }
        paramMap.put(key, value);
        return this;
    }

    public OkHttpUtil get() {
        request = new Request.Builder().get();
        buildUrlWithParameters();
        return this;
    }

    public OkHttpUtil post(boolean isJsonPost) {
        okhttp3.RequestBody requestBody = isJsonPost ? createJsonRequestBody() : createFormRequestBody();
        request = new Request.Builder().post(requestBody).url(url);
        return this;
    }

    public OkHttpUtil post(String jsonString) {
        okhttp3.RequestBody requestBody = okhttp3.RequestBody.create(jsonString, JSON_MEDIA_TYPE);
        request = new Request.Builder().post(requestBody).url(url);
        return this;
    }

    public String sync() throws IOException {
        setHeader(request);
        Response response = CLIENT.newCall(request.build()).execute();
        return response.body() != null ? response.body().string() : null;
    }

    public Response syncResponse() {
        try {
            setHeader(request);
            return CLIENT.newCall(request.build()).execute();
        } catch (IOException e) {
            logger.error("syncResponse 同步请求失败", e);
        }
        return null;
    }

    private void setHeader(Request.Builder request) {
        if (headerMap != null) {
            for (Map.Entry<String, String> entry : headerMap.entrySet()) {
                request.addHeader(entry.getKey(), entry.getValue());
            }
        }
    }

    private void buildUrlWithParameters() {
        StringBuilder urlBuilder = new StringBuilder(url);
        if (paramMap != null) {
            urlBuilder.append("?");
            try {
                for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
                    urlBuilder
                            .append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8))
                            .append("=")
                            .append(URLEncoder.encode(String.valueOf(entry.getValue()), StandardCharsets.UTF_8))
                            .append("&");
                }
            } catch (Exception e) {
                logger.error("初始化Get请求失败", e);
            }
            urlBuilder.deleteCharAt(urlBuilder.length() - 1);
        }
        request.url(urlBuilder.toString());
    }

    private okhttp3.RequestBody createJsonRequestBody() {
        String json = paramMap != null ? JSON.toJSONString(paramMap) : "";
        return okhttp3.RequestBody.create(json, JSON_MEDIA_TYPE);
    }

    private okhttp3.RequestBody createFormRequestBody() {
        FormBody.Builder formBody = new FormBody.Builder();
        if (paramMap != null) {
            Set<Map.Entry<String, Object>> entries = paramMap.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                formBody.add(entry.getKey(), String.valueOf(entry.getValue()));
            }
        }
        return formBody.build();
    }
}
